/*
 * MenuAction.java
 *
 * Created on 2007��7��26��, ����4:36
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package com.afaker.rss.gui.action;

import com.afaker.rss.common.GeneralUtils;
import com.afaker.rss.context.ApplicationContext;
import com.afaker.rss.context.ResourceContext;
import com.afaker.rss.feed.biz.FeedFetcher;
import com.afaker.rss.feed.biz.ROMEFeedFetcher;
import com.afaker.rss.feed.FeedSet;
import com.afaker.rss.feed.ChannelList;
import com.afaker.rss.feed.Feed;
import com.afaker.rss.gui.tree.RSSTreeNode;
import com.afaker.rss.gui.table.XMLTableModel;
import com.afaker.rss.gui.Window;
import com.sun.syndication.fetcher.FetcherException;
import com.sun.syndication.io.FeedException;
import com.afaker.rss.xml.XMLDocumentFactory;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.table.TableModel;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.jdom.DefaultJDOMFactory;
import org.jdom.Document;
import org.jdom.Element;

/**
 *
 * @author bruce
 */
public class MenuAction extends AbstractAction {

    private static JTree channelTree;
    //private MenuActionListener listener;
    private static JToolBar toolBar;
    private static Window window;
    private static DefaultTreeModel treeModel;
    private static ChannelList feedList;
    private static TableModel tableModel;
    private static FeedSet feedSet;
    private static XMLDocumentFactory xml;
    private String favoriteFile = ResourceContext.getResourceContext().getProperty("favorite.file");
    private ApplicationContext appContext = ApplicationContext.getApplicationContext();
    public static final String ROOT_NODE_NAME = "RSSClient";
    public static final String FAVORITE_NODE_NAME = "favorite";
    public static final String CATEGORY_NODE_NAME = "category";
    public static final String CHANNEL_NODE_NAME = "channel";
    public static final String FAVORITE_N_CATEGORY_NAME_ATTRIBUTE_NAME = "name";
    public static final String TITLE_ATTRIBUTE_NAME = "title";
    public static final String FEEDNAME_ATTRIBUTE_NAME = "feedname";
    public static final String DESCRIPTION_ATTRIBUTE_NAME = "description";
    public static final String AUTHOR_ATTRIBUTE_NAME = "author";
    public static final String URI_ATTRIBUTE_NAME = "uri";
    public static final String LINK_ATTRIBUTE_NAME = "link";

    /**
     * Creates a new instance of MenuAction
     */
    public MenuAction(String name) {
        super(name);
        ImageIcon icon = null;
        if (name.equals(appContext.getProperty("channel.new.button.text"))) {
            icon = new ImageIcon(ResourceContext.getResourceContext().getProperty("channel.new.icon"));
            //ADD Tooltip
            putValue(SHORT_DESCRIPTION, appContext.getProperty("channel.new.button.tooltip"));
        } else if (name.equals(appContext.getProperty("category.new.button.text"))) {
            icon = new ImageIcon(ResourceContext.getResourceContext().getProperty("category.new.icon"));
            putValue(SHORT_DESCRIPTION, appContext.getProperty("category.new.button.tooltip"));
        } else if (name.equals(appContext.getProperty("delete.button.text"))) {
            icon = new ImageIcon(ResourceContext.getResourceContext().getProperty("delete.icon"));
            putValue(SHORT_DESCRIPTION, appContext.getProperty("delete.button.tooltip"));
        } else if (name.equals(appContext.getProperty("update.button.text"))) {
            icon = new ImageIcon(ResourceContext.getResourceContext().getProperty("update.icon"));
            putValue(SHORT_DESCRIPTION, appContext.getProperty("update.button.tooltip"));
        }
        //Add icon
        putValue(SMALL_ICON, icon);
    }

    public MenuAction(String name, KeyStroke key) {
        this(name);
        if (key != null) {
            putValue(ACCELERATOR_KEY, key);
        }
    }
    /*  public void addListener(MenuActionListener li) {
    this.listener = li;
    }*/
    //Pass necessary parameters
    public static void setNecessaryInformation(JTree tree,
            JToolBar tool, Window win, ChannelList list, TableModel tab, XMLDocumentFactory x) {
        channelTree = tree;
        toolBar = tool;
        window = win;
        feedList = list;
        tableModel = tab;
        xml = x;
    }

    public void setFeedSet(FeedSet feedSet) {
        MenuAction.feedSet = feedSet;
    }

    public void actionPerformed(ActionEvent e) {
        //Get the node selected.
        if (channelTree == null) {
            return;
        }
        //Get the current selectedNode
        treeModel = (DefaultTreeModel) channelTree.getModel();
        TreePath path = channelTree.getSelectionPath();
        RSSTreeNode node = null;
        if (path != null) {
            node = (RSSTreeNode) path.getLastPathComponent();
        } else {
            return;
        }
        if (node == null) {
            return;
        }
        //Get the event source object.
        Object obj = e.getSource();
        JOptionPane pane = new JOptionPane();

        Element parent = xml.getRootElement();
        Element favorite = (Element) parent.getChild(FAVORITE_NODE_NAME);
        //temp element stores the node element we want to do stuffs.
        Element temp = (Element) node.getUserObject();
        String response;

        /**New channel menu is clicked...*/
        if (obj.equals(toolBar.getComponentAtIndex(0))) {
            //If the node selected is a channel or the root node,an error comes up.
            if (!node.getAllowsChildren() || node.isRoot()) {
                JOptionPane.showInternalMessageDialog(window.getContentPane(),
                        appContext.getProperty("category.add2root.message"),
                        appContext.getProperty("app.name"), JOptionPane.WARNING_MESSAGE);
                return;
            }
            //response is a value of url entred by user returned by the dialog.
            response = JOptionPane.showInternalInputDialog(window.getContentPane(),
                    appContext.getProperty("channel.add.dialog.message"),
                    appContext.getProperty("app.name"), JOptionPane.INFORMATION_MESSAGE);
            final String resp = response;
            //If the url is null,return.
            if (resp == null) {
                return;
            }

            //If the channel list has contain the channel,do not add the channel.
            if (feedList.contains(response)) {
                return;
            }
            Thread thread = new Thread(new Runnable() {

                public void run() {
                    TreePath path = channelTree.getSelectionPath();

                    RSSTreeNode node = null;
                    if (path != null) {
                        node = (RSSTreeNode) path.getLastPathComponent();
                    } else {
                        return;
                    }
                    if (node == null) {
                        return;
                    }
                    Element temp = (Element) node.getUserObject();
                    ROMEFeedFetcher fetcher;
                    Feed feedEntity = null;
                    Element item = null;
                    try {
                        fetcher = new ROMEFeedFetcher(resp);
                        feedEntity = fetcher.getFeed();
                        item = new Element(CHANNEL_NODE_NAME);
                        item.setText(resp);
                        item.setAttribute(TITLE_ATTRIBUTE_NAME, feedEntity.getTitle() + "");
                        System.out.println(feedEntity.getTitle());
                        item.setAttribute(FEEDNAME_ATTRIBUTE_NAME, feedEntity.getTitle() + "");
                        item.setAttribute(DESCRIPTION_ATTRIBUTE_NAME, feedEntity.getDescription() + "");
                        item.setAttribute(AUTHOR_ATTRIBUTE_NAME, feedEntity.getAuthor() + "");
                        item.setAttribute(URI_ATTRIBUTE_NAME, feedEntity.getURI() + "");
                        item.setAttribute(LINK_ATTRIBUTE_NAME, feedEntity.getLink() + "");
                        temp.addContent(item);
                        xml.outputToFile(favoriteFile);
                        //Download the feed file to disk.
                        fetcher.download(GeneralUtils.getLocalChannelName(feedEntity.getTitle(), true, true));
                    } catch (FeedException ex) {
                        ex.printStackTrace();
                        //If something is wrong,show the error.
                        window.showError(resp, ex.getMessage() + "\n" + ex.getCause().getMessage());
                        return;
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    //Add the feed uri to channel list.
                    if (!feedList.addChannelToList(resp)) {
                        return;
                    }
                    //Add the channel to favorite file.

                    RSSTreeNode newNode = new RSSTreeNode(item);
                    newNode.setAllowsChildren(false);
                    node.add(newNode);
                    //Create a marked file.
                    createMarkedXMLFile(feedEntity.getTitle(), false);
                    //Refresh the node
                    treeModel.reload(node);
                    System.out.println(appContext.getProperty("channel.add.success"));
                }
            });
            thread.start();
        } /**New category menu is clicked...*/
        else if (obj.equals(toolBar.getComponentAtIndex(1))) {
            if (!node.getAllowsChildren()) {
                JOptionPane.showInternalMessageDialog(window.getContentPane(),
                        appContext.getProperty("add2channel.error"),
                        appContext.getProperty("app.name"), JOptionPane.WARNING_MESSAGE);
                return;
            }
            response = JOptionPane.showInternalInputDialog(window.getContentPane(),
                    appContext.getProperty("category.add.message"),
                    appContext.getProperty("app.name"), JOptionPane.INFORMATION_MESSAGE);
            if (response == null) {
                return;
            }
            Element category = new Element(CATEGORY_NODE_NAME);
            category.setAttribute(FAVORITE_N_CATEGORY_NAME_ATTRIBUTE_NAME, response);
            if (!node.isRoot()) {
                temp.addContent(category);
            } else {
                favorite.addContent(category);
            }
            //Add the node to the xml file "favorite.xml"
            xml.outputToFile(favoriteFile);
            //Add the node to tree
            RSSTreeNode newNode = new RSSTreeNode(category);
            node.add(newNode);
            treeModel.reload(node);
            System.out.println(appContext.getProperty("category.add.success"));
        } /**Delete a favorite directory or a feed file.*/
        else if (obj.equals(toolBar.getComponentAtIndex(2))) {
            int confirm = JOptionPane.showInternalConfirmDialog(window.getContentPane(),
                    appContext.getProperty("node.delete.message"),
                    appContext.getProperty("app.name"),
                    JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
            if (confirm == JOptionPane.YES_OPTION) {
                Element p = temp.getParentElement();
                if (p.getName().equals(ROOT_NODE_NAME)) {
                    JOptionPane.showInternalMessageDialog(window.getContentPane(),
                            appContext.getProperty("category.delete.root.message"),
                            appContext.getProperty("app.name"), JOptionPane.WARNING_MESSAGE);
                    return;
                }
                //Remove from favorite.xml file
                p.removeContent(temp);
                xml.outputToFile(favoriteFile);
                RSSTreeNode nodeParent = (RSSTreeNode) node.getParent();
                nodeParent.remove(node);
                ArrayList list = new ArrayList();

                list = getAllFeedElements(temp);
                for (int i = 0; i < list.size(); i++) {
                    RSSTreeNode selectedNode = new RSSTreeNode((Element) list.get(i));
                    if (selectedNode.isFeed()) {
                        feedList.removeChannel(selectedNode.getFeedURL());
                        String fileName = GeneralUtils.getLocalChannelName(selectedNode.getFeedName(), false, true);
                        File file = new File(fileName);
                        file.delete();
                        fileName = GeneralUtils.getLocalChannelName(selectedNode.getFeedName(), true, true);
                        file = new File(fileName);
                        file.delete();
                    }
                }
                treeModel.reload(nodeParent);
                if (tableModel instanceof XMLTableModel) {
                    ((XMLTableModel) tableModel).setNullData();
                }
            }
        } /**Update a single feed or all feeds under the current category*/
        else if (obj.equals(toolBar.getComponentAtIndex(3))) {
            ArrayList list = getAllFeedElements(temp);
            FeedFetcher fetcher = null;
            RSSTreeNode select;
            if (list == null) {
                return;
            }
            for (int i = 0; i < list.size(); i++) {
                select = new RSSTreeNode((Element) list.get(i));
                if (select.isFeed()) {
                    try {
                        fetcher = new ROMEFeedFetcher(select.getFeedURL());
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    } catch (FetcherException ex) {
                        ex.printStackTrace();
                    } catch (FeedException ex) {
                        ex.printStackTrace();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    fetcher.refresh();
                }
            }

        } /**Update all feeds*/
        else if (obj.equals(toolBar.getComponentAtIndex(4))) {
            feedSet.refreshAll();
        }
    }

    public static ArrayList getAllFeedElements(Element temp) {
        ArrayList list = new ArrayList();
        if (temp == null) {
            return null;
        }
        if (temp.getName().equals(CATEGORY_NODE_NAME) || temp.getName().equals(FAVORITE_NODE_NAME)) {
            getNext(temp, list);
        } else {
            list.add(temp);
        }
        return list;
    }

    /**Recursive to add the channel element to list*/
    public static void getNext(Element root, ArrayList list) {
        if (root == null) {
            return;
        }
        Iterator it = root.getChildren(CHANNEL_NODE_NAME).listIterator();
        while (it.hasNext()) {
            list.add(it.next());
        }
        if (root.getChildren(CATEGORY_NODE_NAME).size() <= 0) {
            return;
        }
        Iterator it2 = root.getChildren(CATEGORY_NODE_NAME).listIterator();
        while (it2.hasNext()) {
            getNext((Element) it2.next(), list);
        }
    }

    /**Create a xml file that records how many news have been readed.*/
    public static void createMarkedXMLFile(String title, boolean isTemp) {
        DefaultJDOMFactory factory = new DefaultJDOMFactory();
        Element root = new Element(XMLTableModel.FEED_NODE_NAME);
        root.setAttribute(XMLTableModel.NUMBER_ATTRIBUTE_NAME, "0");
        Document document = factory.document(root);
        XMLDocumentFactory.outputToFile(document, GeneralUtils.getLocalChannelName(title, false, true));
    }
}
